package com.yufubao.service.service.applet.authorization.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yufubao.framework.constant.AppletRedisKeysConstant;
import com.yufubao.framework.enums.CommonExceptionEnum;
import com.yufubao.framework.exception.BaseException;
import com.yufubao.framework.util.CopyBean;
import com.yufubao.framework.util.JwtUtil;
import com.yufubao.framework.util.MyCollUtil;
import com.yufubao.framework.interceptor.AppletInterceptor;
import com.yufubao.framework.interceptor.local.LoginUserLoc;
import com.yufubao.framework.result.ResponseResult;
import com.yufubao.model.dto.applet.authorization.AppWxLoginDto;
import com.yufubao.model.dto.applet.authorization.SupplierApplyDto;
import com.yufubao.model.dto.common.PhoneLoginDto;
import com.yufubao.model.pojo.applet.authorization.UserEntity;
import com.yufubao.model.pojo.applet.product.SupplierInfoEntity;
import com.yufubao.service.service.applet.authorization.UserService;
import com.yufubao.service.service.applet.authorization.UserWxPowerService;
import com.yufubao.service.service.applet.product.SupplierInfoService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.yufubao.framework.constant.AppletRedisKeysConstant.SMS_CODE;
import static com.yufubao.framework.constant.GlobalPattern.*;
import static com.yufubao.framework.constant.UserTypeConstant.*;
import static com.yufubao.framework.enums.CommonExceptionEnum.*;
import static com.yufubao.framework.util.SecurityUtils.checkUserLoc;

/**
 * @author 张一恒
 * @version 1.0
 * @description:
 * @date 2024/8/26 11:51
 */
@Slf4j
@Service("userWxPowerService")
public class UserWxPowerServiceImpl implements UserWxPowerService {

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SupplierInfoService supplierInfoService;

    /**
     * @param dto
     * @return com.yufubao.common.result.ResponseResult
     * @description 登录
     * @author zhangyiheng
     * @date 2024/8/26 11:54
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginUserLoc login(AppWxLoginDto dto) {
        try {
            log.info("微信小程序用户登录。。。");
            //根据code获取openid
            WxMaJscode2SessionResult session = new WxMaJscode2SessionResult();

            try {
                log.info("调用微信小程序接口，获取openid。。。。。");
                session = wxMaService.getUserService().getSessionInfo(dto.getCode());
            } catch (WxErrorException e) {
                throw new BaseException(CommonExceptionEnum.WXXCX_LOGIN_CODE_ERROR);
            }

            if (StrUtil.isAllBlank(session.getOpenid(), session.getUnionid())) {
                log.info("调用微信小程序接口，获取openid失败。。。。。");
                throw new BaseException(CommonExceptionEnum.WXXCX_LOGIN_CODE_ERROR);
            }

            UserEntity user = null;
            //先通过unionId查找 用户微信服小程序应用组的唯一标识
            String unionid = session.getUnionid();
            //当前用户在预付宝小程序的唯一标识
            String openid = session.getOpenid();

            user = userService.getOne(Wrappers.<UserEntity>lambdaQuery()
                    .eq(UserEntity::getUnionId, unionid));

            if (Objects.isNull(user)) {
                //查询openid是否存在
                user = userService.getOne(Wrappers.<UserEntity>lambdaQuery()
                        .eq(UserEntity::getOpenId, openid));
            }

            if (!Objects.isNull(user)) {
                //设置token、更新用户信息登录成功
                LoginUserLoc loginUserLoc = this.settingToken(user);
                log.info("调用微信小程序接口，获取用户信息成功。。。。。===》{}", loginUserLoc);
                return loginUserLoc;
            }

            //第一次登录 注册
            //获取用户信息
//            String userInfoStr = StringEscapeUtils.unescapeHtml4(dto.getUserInfo());
//            JSONObject userJsonInfo = JSONObject.parseObject(userInfoStr);
            user = new UserEntity();
            if (StringUtils.isNotBlank(unionid)) {
                user.setUnionId(unionid);
            }
            user.setOpenId(openid);
            String uuid = IdWorker.get32UUID();
            if (StrUtil.isBlank(dto.getNickname())) {
                user.setNickname("预付宝会员" + uuid.substring(uuid.length() - 4));
            } else {
                user.setNickname(dto.getNickname());
            }
            if (StrUtil.isBlank(dto.getAvatar())) {
                user.setAvatarurl("");
            } else {
                user.setAvatarurl(dto.getAvatar());
            }
            user.setRegSource("wx");
            userService.save(user);
            log.info("调用微信小程序接口，注册用户信息成功。。。。。===》{}", user);
            return this.settingToken(user);
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }


    private LoginUserLoc settingToken(UserEntity user) {
        LoginUserLoc loginUserLoc = CopyBean.copyBean(user, LoginUserLoc.class);

        //生成token  jwt

        Map map = JSON.parseObject(JSON.toJSON(loginUserLoc).toString(), Map.class);
        String token = JwtUtil.generate(map);

        loginUserLoc.setAppletToken(token);

        String key = AppletRedisKeysConstant.APPLET_LOGIN + user.getUserId();
        redisTemplate.opsForValue().set(key, loginUserLoc, 1, TimeUnit.DAYS);

        log.info("微信小程序用户登录：settingToken完成");

        return loginUserLoc;
    }

    /**
     * @param dto
     * @return com.yufubao.common.result.ResponseResult
     * @description 手机号验证码登录
     * @author zhangyiheng
     * @date 2024/8/27 11:10
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult phoneLogin(PhoneLoginDto dto) {
        //判断验证码
        String code = dto.getCode();
        String cacheCode = stringRedisTemplate.opsForValue().get(SMS_CODE + dto.getPhone());
        if (StrUtil.isBlank(cacheCode) || StrUtil.isBlank(cacheCode.split("_")[0])) {
            return ResponseResult.errorResult(VALID_SMS_TIME_EXCEPTION);
        } else {
            cacheCode = cacheCode.split("_")[0];
            if (code.equals(cacheCode)) {
                //验证码正确
                stringRedisTemplate.delete(SMS_CODE + dto.getPhone());

                //查询用户是否存在
                UserEntity userInfo = userService.getOne(Wrappers.<UserEntity>lambdaQuery()
                        .eq(UserEntity::getMobile, dto.getPhone()));

                if (!Objects.isNull(userInfo)) {
                    //设置token
                    LoginUserLoc loginUserLoc = this.settingToken(userInfo);
                    //判断是否同时为商家
                    if (Objects.equals(userInfo.getUserType(), USER_TYPE_SHANG)) {
                        //设置商店id
                        List<SupplierInfoEntity> supplierInfos = supplierInfoService.list(Wrappers.<SupplierInfoEntity>lambdaQuery()
                                .eq(SupplierInfoEntity::getUserId, userInfo.getUserId()));
                        if (MyCollUtil.isNotEmpty(supplierInfos)) {
                            List<Long> ids = supplierInfos.stream().map(SupplierInfoEntity::getSupplierInfoId).collect(Collectors.toList());
                            loginUserLoc.setSupplierInfoIds(ids);
                        }

                    }
                    return ResponseResult.okResult(loginUserLoc);
                }

                //没有就注册登录
                //保存用户信息，头像、名称默认
                userInfo = new UserEntity();
                userInfo.setRegSource("短信验证码");
                userInfo.setMobile(dto.getPhone());
                userInfo.setNickname("预付宝会员" + dto.getPhone().substring(dto.getPhone().length() - 4));
                userInfo.setGender(2);
                userInfo.setUserType(USER_TYPE_ORDINARY);
                userService.save(userInfo);
                LoginUserLoc loginUserLoc = this.settingToken(userInfo);
                return ResponseResult.okResult(loginUserLoc);
            } else {
                return ResponseResult.errorResult(DODE_ERROR);
            }
        }
    }

    /**
     * @param dto
     * @return com.yufubao.common.result.ResponseResult
     * @description 用户申请商户
     * @author zhangyiheng
     * @date 2024/8/26 21:23
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult merchantApplication(SupplierApplyDto dto) {
        LoginUserLoc loginUserLoc = checkUserLoc(AppletInterceptor.APPLETTHREADLOCAL);

        //校验手机号或银行卡号
        String code = dto.getCode();
        String cacheCode = null;
        Pattern pattern = null;
        Matcher matcher = null;
        if (Objects.isNull(dto.getMobile())) {
            if (Objects.isNull(dto.getCardNumber()) && Objects.isNull(dto.getReservedNumber())) {
                throw new BaseException(CommonExceptionEnum.FRRZFSBNWK);
            } else {
                pattern = Pattern.compile(CART);
                matcher = pattern.matcher(dto.getCardNumber());
                if (!matcher.matches()) {
                    throw new BaseException(CommonExceptionEnum.YHKHGSCW);
                }
                pattern = Pattern.compile(PHONE);
                matcher = pattern.matcher(dto.getReservedNumber());
                if (!matcher.matches()) {
                    throw new BaseException(CommonExceptionEnum.SJHGSCW);
                }

                cacheCode = stringRedisTemplate.opsForValue().get(SMS_CODE + dto.getReservedNumber());
                if (StrUtil.isBlank(cacheCode) || StrUtil.isBlank(cacheCode.split("_")[0])) {
                    return ResponseResult.errorResult(VALID_SMS_TIME_EXCEPTION);
                }
                if (code.equals(cacheCode)) {
                    return ResponseResult.errorResult(DODE_ERROR);
                }
            }
        } else {
            pattern = Pattern.compile(PHONE);
            matcher = pattern.matcher(dto.getMobile());
            if (!matcher.matches()) {
                throw new BaseException(CommonExceptionEnum.SJHGSCW);
            }
            cacheCode = stringRedisTemplate.opsForValue().get(SMS_CODE + dto.getMobile());
            if (StrUtil.isBlank(cacheCode) || StrUtil.isBlank(cacheCode.split("_")[0])) {
                return ResponseResult.errorResult(VALID_SMS_TIME_EXCEPTION);
            }
            if (code.equals(cacheCode)) {
                return ResponseResult.errorResult(DODE_ERROR);
            }
        }

        //门脸照片
        if (StrUtil.isNotBlank(dto.getShopFrontUrl())) {
            pattern = Pattern.compile(IMAGE_URL);
            matcher = pattern.matcher(dto.getMobile());
            if (!matcher.matches()) {
                throw new BaseException(SHMLTPLJDZCW);
            }
        }


        //创建审核单
        SupplierInfoEntity supplierInfoEntity = CopyBean.copyBean(dto, SupplierInfoEntity.class);
        supplierInfoEntity.setStatus(USER_STATE_REVIEWED);
        supplierInfoEntity.setUserId(loginUserLoc.getUserId());

        supplierInfoService.save(supplierInfoEntity);


        return ResponseResult.ok(SHSQDCJWC);
    }

}
